<template>
  <div class="fx-checkbox-group" :class="{'button-group':isButton}">
    <slot></slot>
  </div>
</template>

<script lang="ts">
import {
  computed,
  defineComponent,
  inject, onBeforeUnmount,
  onMounted,
  PropType,
  provide,
  ref,
  SetupContext,
  watch
} from 'vue'
import mitt, { Emitter } from 'mitt'
import { useIsDefaultSlotName } from '@/base/hooks'
import { ComponentSize, componentSizeArr } from '@/base/types'

export type ModelValue = string | { [key: string]: unknown }

interface CheckboxGroupProps {
  modelValue: Array<ModelValue>;
  disabled: boolean;
  max: number;
  min: number;
  size: ComponentSize;
  valueKey: string;
}

export default defineComponent({
  name: 'checkboxGroup',
  props: {
    // v-model
    modelValue: {
      type: Array as PropType<Array<ModelValue>>,
      required: true,
      default: () => []
    },
    // 禁用
    disabled: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 最大选中个数
    max: {
      type: Number as PropType<number>,
      default: 999999
    },
    // 最小选中个数
    min: {
      type: Number as PropType<number>,
      default: 0
    },
    // 大小
    size: {
      type: String as PropType<ComponentSize>,
      default: 'default',
      validator (val: ComponentSize): boolean {
        return componentSizeArr.includes(val)
      }
    },
    // 选择对象时 锁定的key值
    valueKey: {
      type: String as PropType<string>,
      default: null
    }
  },
  emits: ['update:modelValue', 'change'],
  setup (props: CheckboxGroupProps, ctx: SetupContext) {
    // 向子级传送数据
    const checkboxMitt: Emitter = mitt()
    // 当前选中数组
    const checkboxGroupValue = ref<Array<ModelValue>>(props.modelValue)
    // 是否需要按钮border
    const isButton = useIsDefaultSlotName('FCheckboxButton')
    // 接收formItem mitt 监听器
    const formItemMitt = inject<Emitter['emit'] | undefined>('formItemMitt', undefined)

    // 当前选中
    provide('checkboxGroupValue', computed(() => props.modelValue))
    // 禁用
    provide('checkboxGroupDisabled', props.disabled)
    // 禁用
    provide('checkboxGroupSize', props.size)
    // 对象时 选择key
    provide('checkboxGroupValueKey', props.valueKey)
    // 数据传送监听
    provide('checkboxGroupMittEmit', checkboxMitt.emit)
    // 选中个数限制
    provide('checkboxGroupNumber', {
      max: props.max,
      min: props.min
    })

    const handleCheckboxMitt = (val: ModelValue | undefined): void => {
      if (!val) return
      const checkedIndex: number = checkboxGroupValue.value.findIndex((item: ModelValue) => {
        if (typeof item === 'object' && typeof val === 'object' && props.valueKey) return item[props.valueKey] === val[props.valueKey]
        return item === val
      })
      // 当选择少于最小选择数时 触发`
      if (isMin(checkedIndex, val)) return
      if (checkedIndex < 0) {
        checkboxGroupValue.value.push(val)
      } else {
        checkboxGroupValue.value.splice(checkedIndex, 1)
      }
    }

    const isMin = (checkedIndex: number, val: ModelValue): boolean => {
      const data: ModelValue = checkboxGroupValue.value[checkedIndex]
      if (checkboxGroupValue.value.length > props.min) return false
      if (typeof data === 'object' && typeof val === 'object' && props.valueKey) return data[props.valueKey] === val[props.valueKey]
      return data === val
    }

    watch(() => props.modelValue, (val: Array<ModelValue>): void => {
      checkboxGroupValue.value = val
    }, { deep: true })
    watch(checkboxGroupValue, (val: Array<ModelValue>): void => {
      ctx.emit('change', val)
      ctx.emit('update:modelValue', val)
      // 发送当前的数据给formItem
      if (formItemMitt) formItemMitt('formItemValue', val)
    }, { deep: true })

    onMounted(() => {
      checkboxMitt.on<string | undefined>('checkboxMitt', handleCheckboxMitt)
      // 发送当前的数据给formItem
      if (formItemMitt) formItemMitt('formItemValue', checkboxGroupValue)
    })

    onBeforeUnmount(() => {
      checkboxMitt.off('checkboxMitt', handleCheckboxMitt)
    })

    return {
      isButton,
      checkboxGroupValue
    }
  }
})
</script>
